package prender;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;

/**
 * Wrapper for HttpServletRequest.
 * attribute
 *     For read, it will lookup a local copy, if not found, then delegate to original request
 *     For write, it will make a local copy. The idea is, it's original request may have many
 *     wrapper that is being processed at same time, if we delegate write attribute to the 
 *     original request, it may step on each other and cause undesired behavior.
 * @author Stone Zhong
 *
 */

class MyRequest extends HttpServletRequestWrapper {

	static final String MY_REQUEST_KEY	= "prender.MyRequest";

	private Map<String, Object> attributes = new HashMap<String, Object>();
	
	private ReentrantLock attributeLock = new ReentrantLock();
	
	MyRequest(HttpServletRequest request) {
		super(request);
		attributes.put(MY_REQUEST_KEY, this);
	}
	
	@Override
	public Object getAttribute(String name) {
		attributeLock.lock();
		try {
			if (attributes.containsKey(name)) {
				return attributes.get(name);
			}
			return getRequest().getAttribute(name);	
		} finally {
			attributeLock.unlock();
		}
		
	}
	
	@Override 
	public void setAttribute(String name, Object value) {
		attributeLock.lock();
		try {
			attributes.put(name,  value);
		} finally {
			attributeLock.unlock();
		}
	}
	
	@Override 
	public void removeAttribute(String name) {
		attributeLock.lock();
		try {
			attributes.remove(name);
		} finally {
			attributeLock.unlock();
		}
	}

	// TODO: merge this attributes and original request's attributes
	@Override 
	public Enumeration<?> getAttributeNames() {
		return getRequest().getAttributeNames();
	}
	
	private TopContext topContext;
	TopContext getTopContext() {
		return topContext;
	}
	void setTopContext(TopContext topContext) {
		this.topContext = topContext;
	}

	private MyResponse response;
	MyResponse getResponse() {
		return response;
	}
	void setResponse(MyResponse response) {
		this.response = response;
	}
	
}
